home *** CD-ROM | disk | FTP | other *** search
/ Scene 96 / Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso / misc / coding / vgacodng / part05.txt < prev    next >
Text File  |  1996-11-22  |  19KB  |  369 lines

  1.  
  2.                              VGA-Kurs - Part #5
  3.  
  4. Herzlich Willkommen zu 'T.C.P.'s Beginners Guide To VGA Coding', Part V.
  5. In diesem Teil werden wir den in der Demo-Scene am meisten genutzten
  6. Videomodus besprechen, den Mode-X.
  7. Der Mode-X ist, wie viele sicherlich vermuten, kein Standardmodus der VGA.
  8. Trotzdem ist er eigentlich ein sehr gewöhnlicher Videomodus, der wie die
  9. Hires-Modi aufgebaut ist, d.h. er wird nicht direkt, wie beim Modus 13h,
  10. sondern über Planes adressiert.
  11. Eigentlich ist der Modus 13h ja auch eine Abart des Mode-X, und nicht
  12. umgekehrt. Die Entwickler der VGA-Karte wollten den Modus 13h möglichst einfach
  13. programmierbar machen. Bei den Vorgängern der VGA wurde der Bildschirmspeicher
  14. immer in Verbindung mit Planes angesprochen. Diese sind im Modus 13h durch
  15. Abschalten des sog. Chain-4-Modus nicht aktiv, und man kann den
  16. Bildschirmspeicher direkt ansprechen.
  17. Eine Plane ist sozusagen ein Bildschirm. Im EGA-Modus z.B. muß man, um ein Pixel
  18. zu setzen, erst die Plane bestimmen, auf die der Punkt gesetzt werden soll, um
  19. anschließend den Punkt an die gewünschten Koordinaten zu setzen. Dies erscheint
  20. komplizierter als beim Modus 13h, jedoch stößt man, wenn man nur in diesem
  21. Modus 13h programmiert, sehr bald auf Grenzen. Ein Beispiel:
  22. Der PC wurde im Laufe der Jahre immer weiter entwickelt, genau wie die
  23. VGA-Karten. Schneller, mehr Speicher, höhere Auflösungen. Doch trotz aller
  24. Rechenpower gibt es eine Einschränkung: Bei manchen, sehr rechenaufwendigen
  25. VGA-Operationen, schafft es die Hardware einfach nicht, den Bildschirm
  26. innerhalb eines Strahlrücklaufes (Retrace) vollständig darzustellen.
  27. Bewegt sich nun zufälligerweise genau in dem Zeitpunkt, in dem das Bild
  28. aufgebaut wird, der Kathodenstrahl über den Schirm, hat das fatale Folgen.
  29. In der oberen Hälfte des Bildschirms, die schon neu aufgebaut wurde, ist das
  30. nächste Frame zu sehen, in der unteren Hälfte noch das alte. Man muß also vor
  31. der Bildschirmoperation abwarten, bis der Retrace vorüber ist, und dann das
  32. Bild aufbauen. Was aber, wenn während der kurzen Zeit, in der kein Neuaufbau
  33. des Bildes erfolgt, nicht genug Zeit ist, um z.B. ein komplexes Vektorgebilde
  34. darzustellen?
  35. Jetzt muß eine zweite Bildschirmseite her, auf der man das Bild berechnen, und
  36. dann -schwupp- nach dem Bildschirmaufbau auf den Screen kopieren kann.
  37. Woher aber bekommt man zusätzliche Seiten (Pages)? In der letzen Ausgabe haben
  38. wir uns mit dem Virtual Screen beschäftigt, einer simulierten zweiten Page,
  39. die in den Arbeitsspeicher eingeblendet wird.
  40. Diese Methode erfüllt zwar ihren Zweck, jedoch hat sie einige gravierende
  41. Nachteile:
  42. 1. Ein solcher Virtual Screen beansprucht 64000 Byte Arbeitsspeicher. Das ist
  43. an sich nicht so viel, in einigen Sonderfällen benötigt man allerdings
  44. mehr als einen VS, und dann kann's schon mal eng werden.
  45. 2. Um den Inhalt des VS auf den Screen zu kopieren, müssen 64000 Byte
  46. verschoben werden, was einige Rechenzeit beansprucht, und auf langsameren
  47. Rechnern zu Problemen führen kann.
  48. Diese Nachteile haben wir beim Mode-X nicht, hier werden ganze 4 Pages in die
  49. 64 KB des Bildschirmspeichers gepackt, d.h. es wird kein zusätzlicher
  50. Arbeitsspeicher benötigt und, das wichtigste, eine Page ist nur 16000 Byte
  51. groß, es wird also nur ein Viertel der Rechenzeit benötigt, die beim VS nötig
  52. wäre.
  53. Aber wie in aller Welt soll das funktionieren?
  54. Ganz einfach, wie zu Beginn gesagt, muß beim Mode-X erst die Plane bestimmt
  55. werden, auf die geschrieben/von der gelesen werden soll. Also steht ein Byte
  56. im Bildschirmspeicher für vier Pixel auf dem Screen. Die ersten 16000 Byte
  57. stehen demnach für die 64000 Pixel der ersten Page, die Bytes 16000 bis
  58. 31999 für die der zweiten Page, usw.
  59. Ach so, paßt auf, daß ihr die Begriffe 'Page' und 'Plane' nicht durcheinander
  60. bringt, das sind zwei grundverschiedene Dinge.
  61. Man kann sich die Planes wie vier übereinandergelegte Ebenen vorstellen. Sucht
  62. man sich einen Punkt auf der ersten Ebene, hat man noch 3 auf den anderen
  63. Ebenen, die die gleichen Koordinaten haben. Will man den Punkt also genau
  64. definieren, muß auch die Plane dazu angegeben werden.
  65. Auf der ersten Plane liegen alle Punkte, die durch 4 dividiert den Rest 0
  66. ergeben, auf der zweiten die, die den Rest 1 ergeben, usw.
  67. Ein Beispiel: Will man das dritte Pixel der ersten Page lesen, selektiert man
  68. zuerst Plane 3 (3 div 4 = 0, Rest 3), und liest nun das erste Byte des
  69. Bildschirmspeichers.
  70. Soll stattdessen das 23456. Pixel der dritten Page beschrieben werden, wird es
  71. etwas komplizierter, hier benötigt man konkrete Formeln zur Bestimmung des
  72. Offsets und der Plane, hier kommen sie:
  73. Offset = (Y-Koord * 320 + X-Koord) div 4
  74. Dies können wir umformen zu:
  75. Offset = Y-Koord * 80 + X-Koord div 4,
  76. wobei wir das 'div 4' durch ein schnelleres 'shr 2' ersetzen können.
  77. Die Formel zur Bestimmung der Plane:
  78. Plane = X-Koord mod 4,
  79. also der Rest der Division X-Koord div 4.
  80. Im Modus 13h wird diese Berechnung automatisch vorgenommen, um den einfachen
  81. Zugriff zu ermöglichen.
  82. Doch nun zuerst zum Wichtigsten, dem Setzen des Mode-X. Dazu müssen zuerst der
  83. Chain-4-Mechanismus und der Odd/Even-Mode, d.h. die Plane Selektion per
  84. unterstem Offset-Bit, wie es im Modus 13h üblich ist, abgeschaltet werden.
  85. Man beschreibt das TS-Register 4, und zwar setzt man Bit 2 und löscht Bit 3.
  86. Da es natürlich unter den Grafikkartenherstellern wie so oft schwarze Schafe
  87. gibt, deren Karten nicht ganz 100% kompatibel sind (Dankeschööön!), sollte der
  88. Speicherzugriff auf Byte-Adressierung umgeschaltet werden.
  89. Hierzu löscht man im CRTC-Register 14h das Bit 6 und setzt es im CRTC 17h.
  90.  
  91. procedure SetModeX;assembler;
  92. asm
  93.   mov     ax,13h        { Zuerst den normalen Modus 13h per BIOS aktivieren }
  94.   int     10h
  95.   mov     dx,3C4h
  96.   mov     al,4                         { TS-Register 4 anwählen }
  97.   out     dx,al
  98.   inc     dx
  99.   in      al,dx                        { Aktuellen Registerinhalt holen }
  100.   and     al,0F7h                      { Bit 2 setzen, Bit 3 löschen }
  101.   or      al,4
  102.   out     dx,al                        { Werte zurückschreiben }
  103.   dec     dx
  104.   mov     ax,0F02h
  105.   out     dx,ax                        { Alle Planes selektieren }
  106.   mov     ax,0A000h                    { VGA-Segment nach ES }
  107.   mov     es,ax
  108.   xor     di,di
  109.   xor     ax,ax
  110.   mov     cx,0FFFFh
  111.   cld
  112.   rep     stosw                        { Bildschirm löschen }
  113.   mov     dx,3D4h
  114.   mov     al,14h                       { CRTC-Register 14h anwählen }
  115.   out     dx,al
  116.   inc     dx
  117.   in      al,dx                        { Aktuellen Registerinhalt holen }
  118.   and     al,0BFh                      { Bit 6 löschen }
  119.   out     dx,al
  120.   dec     dx
  121.   mov     al,17h                       { CRTC-Register 17h anwählen }
  122.   out     dx,al
  123.   inc     dx
  124.   in      al,dx
  125.   or      al,40h                       { Bit 6 setzen }
  126.   out     dx,al
  127. end;
  128.  
  129. Ziemlich langer Code nur für das Setzen eines Videomodus, aber es lohnt sich.
  130. Wie das Setzen erfolgt, könnt ihr den Kommentaren entnehmen.
  131. Nachdem wir also diese Prozedur aufgerufen haben, haben wir also einen schönen
  132. Mode-X Screen vor uns. Toll. Freu. Jubel. Aber was nun?
  133. Natürlich, wie wär's, wenn wir munter und unverfroren ein paar Pixel auf den
  134. Screen knallen würden?
  135.  
  136. procedure XPutPixel(x,y:integer;col:byte);assembler;
  137. asm
  138.   mov     ax,0A000h                    { VGA-Segment nach ES }
  139.   mov     es,ax
  140.   mov     cx,x                         { X-Koord nach CX }
  141.   and     cx,3                         { Plane bestimmen }
  142.   mov     ax,1
  143.   shl     ax,cl                        { Entsprechendes Bit setzen }
  144.   mov     ah,al
  145.   mov     dx,03C4h                     
  146.   mov     al,2                         { Timing-Sequencer Reg. 2 anwählen }
  147.   out     dx,ax                        { Plane setzen }
  148.   mov     ax,80                        { Pixel-Offset bestimmen }
  149.   mul     y                            { Offset = y * 80 + x div 4 }
  150.   mov     di,ax                        { y * 80 nach DI }
  151.   mov     ax,x
  152.   shr     ax,2                         { entspricht AX div 4 }
  153.   add     di,ax                        { x div 4 dazuzählen }
  154.   mov     al,col                       { Farbe nach AL }
  155.   mov     es:[di],al                   { Pixel setzen }
  156. end;
  157.  
  158. Die Prozedur selektiert automatisch die richtige Plane und setzt das Pixel.
  159. Logisch, daß die Adressierung des Pixels mehr Zeit braucht als im Modus 13h,
  160. diese Geschwindigkeitsnachteile werden aber durch die oben erwähnten 4 Pages
  161. wieder wettgemacht.
  162. Wollen wir nun auf die zweite Page ein Pixel setzen, müssen wir nur beim
  163. Aufrufen der XPutPixel-Prozedur 200 auf den Y-Wert aufaddieren.
  164. Wenn wir auf eine andere Page umschalten wollen, so daß diese auf dem
  165. Bildschirm sichtbar wird, brauchen wir diese Prozedur:
  166.  
  167. procedure XSetStart(Adr:word);assembler;
  168. asm
  169.   mov     dx,3D4h
  170.   mov     al,0Ch                       { CRTC-Register 0Ch }
  171.   mov     ah,byte ptr Adr + 1          { Bits 15-8 abschicken }
  172.   out     dx,ax
  173.   mov     al,0Dh                       { CRTC-Register 0Dh }
  174.   mov     ah,byte ptr Adr              { Bits 7-0 abschicken }
  175.   out     dx,ax
  176. end;
  177.  
  178. Diese Prozedur kann übrigens in sämtlichen Videomodi angewendet werden,
  179. allerdings macht es nur Sinn, wenn man mehrere Bildschirmseiten hat, wie z.B.
  180. im Modus 640x480x16 oder auch im Textmodus.
  181. Will man also auf Page 2 umschalten, geben wir als Parameter 16000 an, bei
  182. Page 3 32000 und bei Page 4 48000. Mit dem Parameter 0 gelangen wir wieder
  183. zurück auf die erste Page. Natürlich kann man auch einen Wert wie 8000 angeben,
  184. um die zweite Hälfte der ersten und die erste Hälfte der zweiten Page auf dem
  185. Bildschirm zu haben. Merkt ihr was? Diese Prozedur läßt sich sehr elegant für
  186. ein Scrolling einsetzen, indem man den Wert einfach stufenweise erhöht.
  187. Das hatten wir doch schon im vorletzten Teil! Eine Ergänzung dieser Technik
  188. findet ihr weiter unten.
  189. Am Anfang war die Rede davon, daß man für eine saubere Spritedarstellung oder
  190. ähnliches sorgen kann, indem man das Bild unsichtbar auf der zweiten Page
  191. berechnet und dann auf den Screen kopiert. Der Code dazu:
  192.  
  193. procedure CopyPage(ziel,quelle:word);assembler;
  194. asm
  195.   push    ds                           { DS wird verändert, also sichern }
  196.   mov     dx,3C4h
  197.   mov     ax,0F02h
  198.   out     dx,ax
  199.   mov     dx,3CEh                      { Write Mode 1 }
  200.   mov     ax,4105h
  201.   out     dx,ax
  202.   mov     ax,0A000h             { VGA-Segment nach DS (Quelle) und ES (Ziel) }
  203.   mov     ds,ax
  204.   mov     es,ax
  205.   mov     si,quelle                    { Quelloffset nach SI }
  206.   mov     di,ziel                      { Zieloffset nach DI }
  207.   mov     cx,16000                     { 16000 Bytes kopieren }
  208.   rep     movsb
  209.   mov     dx,3CEh
  210.   mov     ax,4005h
  211.   out     dx,ax
  212.   pop     ds                           { DS wiederherstellen }
  213. end;
  214.  
  215. Als Parameter werden wieder die Offsets der Pages übergeben.
  216. Wenn man also das Hintergrundbild auf Page 2 hat, müßte eine Repeat-Schleife
  217. zur Darstellung von Sprites auf einem Hintergrund ungefähr so aussehen:
  218.  
  219. repeat
  220.   WaitRetrace;
  221.   CopyPage(0,16000);
  222.   DrawTheSprites;
  223. until Bedingung = true;
  224.  
  225. Dabei muß man sich keine Gedanken darüber machen, daß man den Hintergrund
  226. wiederherstellen muß, da er im nächsten Schleifendurchlauf sowieso neu kopiert
  227. und damit der alte überschrieben wird. Und da nur 16000 Byte kopiert werden
  228. müssen, geht das Ganze auch relativ schnell.
  229. Das war der wichtigste Grund für die Benutzung des Mode-X. Aber er hat noch
  230. andere Vorzüge, die der Modus 13h nicht bietet.
  231. Der Modus 13h hat standardmäßig die vertikale Auflösung von 200 Pixeln. Das
  232. ist wohl jedem bekannt. Das Sonderbare ist nur, daß die VGA eine vertikale
  233. Auflösung von 200 gar nicht unterstützt. Es gibt nur die Möglichkeiten 350, 400
  234. oder 480. Aber wie kommt der Modus 13h dann zustande? Tja, die schlauen
  235. IBM-Leute haben sich das so überlegt: Da 320x400 (=128000) Byte nicht in den
  236. Bildschirmspeicher passen, ließ man sich das sog. Double-Scan-Verfahren
  237. einfallen. Es wird durch das Setzen der Bits 0-3 und 7 des CRTC-Reg. 9 aktiviert.
  238. Es tut nichts anderes, als jede Zeile einfach 2 mal darzustellen. Dadurch
  239. kommen wir auf die Auflösung von 200 Zeilen. Aber was hilft uns das jetzt?
  240. Ganz einfach, wenn das Register gesetzt wird, um die Zeilenanzahl zu halbieren,
  241. brauchen wir die Bits nur wieder zu deaktivieren, um wieder 400 Zeilen zu
  242. erhalten. Denn im Mode-X passen die 320x400 Pixel ohne weiteres 2 mal in den
  243. Bildschirmspeicher, auch wenn wir dann auf 2 Pages verzichten müssen.
  244.  
  245. procedure XEnter400;assembler;
  246. asm
  247.   mov     dx,3D4h
  248.   mov     al,9                         { CRTC-Register 9 anwählen }
  249.   out     dx,al
  250.   inc     dx
  251.   in      al,dx                        { Aktuellen Registerinhalt holen }
  252.   and     al,70h                       { Bits 0-3 und 7 löschen }
  253.   out     dx,al
  254. end;
  255.  
  256. Durch die verschiedensten Registermanipulationen lassen sich alle möglichen
  257. Auflösungen erreichen, das geht von 256x200 über 376x282 bis 512x480, wobei wir
  258. diese ca. 20 verschiedenen Auflösungen hier nicht besprechen wollen, das würde
  259. nun wirklich zu weit führen. Wer sich für diese VGA-Spielereien interessiert,
  260. soll sich eine ausführliche VGA-Referenz kaufen oder eine der zahlreichen guten
  261. Mode-X Dokumentationen holen, die durch viele Mailboxen geistern.
  262. Kommen wir zu einem weiteren Punkt, wegen dem der Mode-X häufig und gerne
  263. eingesetzt wird: Full-Screen-Scrolling.
  264. Dies ist im Mode-X dank der 4 Pages wirklich kinderleicht zu programmieren.
  265. Es ist ein Scrolling in alle denkbaren Richtungen möglich. Dabei gibt es
  266. allerdings zwei verschiedene Sichtweisen. Aus der Sicht des Programmierers
  267. wird der Screen wie ein Ausschnitt über den Hintergrund bewegt. Aus der Sicht
  268. des Users wird der Hintergrund unter dem Screen bewegt. Dies erscheint
  269. belanglos, es gibt aber einen gravierenden Unterschied zwischen diesen beiden
  270. Sichtweisen, der leicht Verwirrung stiften kann. Ein Beispiel: Ein Scrolly
  271. scrollt zur besseren Lesbarkeit von unten nach oben. Doch der Programmierer
  272. bewegt dabei den Screen von oben nach unten, d.h. die Startadresse des Screens
  273. muß erhöht werden, um das Bild von unten nach oben wandern zu lassen.
  274. Will man allerdings nicht nur nach oben oder nach unten, sondern in alle
  275. Richtungen scrollen, z.B. in einem Actionspiel o.ä., muß der Bildschirm erst
  276. so vorbereitet werden, als ob die vier Pages ein Quadrat bilden würden. Dies
  277. erreichen wir durch das Aktivieren des 160-Byte-Modus. Nach dem Aufrufen der
  278. folgenden Prozedur ist der VGA-Speicher wie ein 640x400-Screen aufgebaut, d.h.
  279. wir können den Ausschnitt des Bildschirms (320x200) beliebig über diesen großen
  280. Bildschirm bewegen. Dazu wird das CRTC-Register 13h mit dem Wert 80 beschrieben
  281. (der normale Wert ist 40), um die virtuelle horizontale Auflösung zu verdoppeln.
  282. Wie dies genau funktioniert, will ich jetzt nicht erklären, das würde zu weit
  283. führen. Wichtig ist nur, daß es funktioniert.
  284.  
  285. procedure XDouble;assembler;
  286. asm
  287.   mov     dx,3D4h                      { CRTC-Register 13h anwählen }
  288.   mov     ax,5013h                     { auf 80 setzen (doppelte Breite) }
  289.   out     dx,ax
  290. end;
  291.  
  292. Um das Prinzip des Scrollings in verschiedene Richtungen zu verdeutlichen,
  293. folgt nun zum Schluß noch einmal ein Beispiel-Programm, das den kompletten
  294. virtuellen 640x400-Screen mit Pixeln vollschreibt und anschließend scrollt.
  295.  
  296. uses crt;
  297. var x,y,dirx,diry : word;
  298. { Hier die Prozeduren SetModeX, WaitRetrace, XSetStart, XDouble und
  299.   XPutPixel einfügen }
  300. begin
  301.   setmodex;                            { Mode-X setzen }
  302.   xdouble;                             { 160-Byte Modus einschalten }
  303.   for x := 0 to 319 do                 { Alle 4 Pages mit Müll füllen }
  304.     for y := 0 to 799 do xputpixel(x,y,random(256));
  305.   x := 1;                              { Startposition }
  306.   y := 160;
  307.   dirx := 1;
  308.   diry := 160;
  309.   repeat
  310.     inc(x,dirx);                       { Bildausschnitt weiterbewegen }
  311.     inc(y,diry);
  312.     delay(10);
  313.     WaitRetrace;
  314.     XSetStart(y+x);                     { Neue Startadresse setzen }
  315.     if (x = 80) or (x = 1) then dirx := -dirx;
  316.     if (y = 32000) or (y = 160) then diry := -diry;
  317.     { Richtung umkehren, wenn am Rand angekommen }
  318.   until keypressed;
  319.   readkey;
  320.   asm mov ax,3; int 10 end;
  321. end.
  322.  
  323. Wer einen Loader für 640x400-Bilder hat, kann ja statt dem Pixelmüll mal ein
  324. schönes Hintergrundbild laden.
  325.  
  326. Weitere empfehlenswerte Mode-X Kurse:
  327. 'Assembler-Kurs - Der Mode X' von Midnight/Knockout, Deutsch (in Blackmail #10)
  328. 'Introduction to Mode X' von Robert Schmidt, Englisch (in PCGPE 1.0)
  329. Außerdem die Mode-X-Libraries von Draeden/VLA und Matt Pritchard.
  330.  
  331. OK, Freunde, das war's für diesmal, für mich war es der am schwersten zu
  332. erklärende Teil bis jetzt, ich hoffe, ihr habt alles kapiert, wenn nicht, lest
  333. es euch noch mal durch, es ist wirklich nicht leicht. Wenn ihr es dann immer
  334. noch nicht versteht, liegt es wohl an meinen Formulierungen. In dem Fall könnt
  335. ihr euch aber noch eine andere Referenz zu dem Thema aus den obengenannten
  336. Quellen ziehen.
  337. Im nächsten Teil geht's um ein Thema, über das ich schon viele Fragen aber
  338. wenig Antworten gelesen habe: Wie stelle ich eigentlich ein Bild dar, das ich
  339. gezeichnet habe?
  340. Wir werden Loader für PCX und RAW-Grafiken besprechen und vielleicht werde ich
  341. noch einiges über Bilddatenkompression schreiben.
  342. Das wird zwar für die VGA-Freaks da draußen ein ziemlich langweiliger Artikel,
  343. aber ich bin sicher, daß sich einige Anfänger, die sich die Zähne an diesem
  344. Problem ausgebissen haben, gern einen Artikel darüber hätten. Falls ich da
  345. völlig falsch liege, könnt ihr's mir ja sagen. Bis dann!
  346.  
  347.  
  348.  
  349.  
  350.  
  351. [ This text copyright (c) 1995-96 Johannes Spohr. All rights reserved. ]
  352. [ Distributed exclusively through PC-Heimwerker, Verlag Thomas Eberle. ]
  353. [                                                                      ]
  354. [ No  part   of  this   document  may  be   reproduced,   transmitted, ]
  355. [ transcribed,  stored in a  retrieval system,  or translated into any ]
  356. [ human or computer language, in any form or by any means; electronic, ]
  357. [ mechanical,  magnetic,  optical,   chemical,  manual  or  otherwise, ]
  358. [ without the expressed written permission of the author.              ]
  359. [                                                                      ]
  360. [ The information  contained in this text  is believed  to be correct. ]
  361. [ The text is subject to change  without notice and does not represent ]
  362. [ a commitment on the part of the author.                              ]
  363. [ The author does not make a  warranty of any kind with regard to this ]
  364. [ material, including,  but not limited to,  the implied warranties of ]
  365. [ merchantability  and fitness  for a particular  purpose.  The author ]
  366. [ shall not be liable for errors contained herein or for incidental or ]
  367. [ consequential damages in connection with the furnishing, performance ]
  368. [ or use of this material.                                             ]
  369.